﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;

namespace GBricks
{
  using Properties;

  [DebuggerStepThrough]
  public static class Argument
  {
    #region NotNull

    [ContractArgumentValidator]
    public static void NotNull(object value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNull(object value, string name, [Localizable(false)] string message) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name, message);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNull<T>(T? value, string name) where T : struct {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNull<T>(T? value, string name, [Localizable(false)] string message) where T : struct {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name, message);
      }//if

      Contract.EndContractBlock();
    }

    #endregion NotNull

    #region NotNullOrEmpty

    [ContractArgumentValidator]
    public static void NotNullOrEmpty(string value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(value.Length == 0) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNullOrEmpty<T>(ICollection<T> value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(value.Count == 0) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNullOrEmpty(ICollection value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(value.Count == 0) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNullOrEmpty<T>(T[] value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(value.Length == 0) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNullOrEmpty<T>(IEnumerable<T> value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(!value.Any()) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void NotNullOrEmpty(IEnumerable value, string name) {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(!value.Cast<object>().Any()) {
        throw ExceptionBuilder.ArgumentEmpty(name);
      }//if

      Contract.EndContractBlock();
    }

    #endregion NotNullOrEmpty

    #region OutOfRange

    [ContractArgumentValidator]
    public static void OutOfRange(bool expression, string name) {
      if(!expression) {
        throw ExceptionBuilder.ArgumentOutOfRange(name);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void OutOfRange(bool expression, string name, [Localizable(false)] string message) {
      if(!expression) {
        throw ExceptionBuilder.ArgumentOutOfRange(name, message);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void OutOfRange<T>(bool expression, T value, string name) {
      if(!expression) {
        throw ExceptionBuilder.ArgumentOutOfRange(name, value);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void OutOfRange<T>(bool expression, T value, string name, [Localizable(false)] string message) {
      if(!expression) {
        throw ExceptionBuilder.ArgumentOutOfRange(name, value, message);
      }//if

      Contract.EndContractBlock();
    }

    #endregion OutOfRange

    [ContractArgumentValidator]
    public static void Check(bool expression, string name, string format = null, params object[] args) {
      if(!expression) {
        throw ExceptionBuilder.Argument(name, format, args);
      }//if

      Contract.EndContractBlock();
    }

    [ContractArgumentValidator]
    public static void TypeIs<T>(T value, Type type, string name) where T : class {
      if(value == null) {
        throw ExceptionBuilder.ArgumentNull(name);
      } else if(type != null && type.IsAssignableFrom(value.GetType())) {
        throw ExceptionBuilder.Argument(name, Resources.ArgumentTypeIsFormat3, name, value.GetType(), type);
      }//if

      Contract.EndContractBlock();
    }
  }
}
